package tmt.usercenter.web.service;

import lombok.Getter;
import org.hibernate.usertype.UserType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tmt.usercenter.web.domain.*;
import tmt.usercenter.web.domain.enums.RoleItem;
import tmt.usercenter.web.domain.enums.TmtUserType;
import tmt.usercenter.web.domain.message.NewUserRole;
import tmt.usercenter.web.repository.ITmtRoleRepo;
import tmt.usercenter.web.repository.ITmtUserRoleRepo;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class TmtUserRoleService extends TmtBaseService<TmtUserRole, Long> {

    @Getter
    private ITmtUserRoleRepo iTmtUserRoleRepo;

    @Autowired
    public TmtUserRoleService(ITmtUserRoleRepo iTmtUserRoleRepo){
        super(iTmtUserRoleRepo, new ArrayList<>());
        this.iTmtUserRoleRepo = iTmtUserRoleRepo;
    }

    @Override
    public void delete(TmtUserRole object) throws Exception {
        TmtUserRole ur = object;
        if (Objects.equals(ur.getRole().getCode(), RoleItem.SUPER_ADMIN.name())
                && ur.getUser().getUserType() == TmtUserType.SYSADMIN)
            throw new Exception("禁止删除SUPER_ADMIN类型的用户的超级管理员（SYSADMIN）角色");
        super.delete(object);
    }

    @Transactional(readOnly = true)
    public boolean existsByUserAndRole(TmtUser user, TmtRole role){
        return iTmtUserRoleRepo.existsByUserAndRole(user, role);
    }

    @Transactional(readOnly = true)
    public List<TmtUserRole> findAllByUserIdAndClientId(Long userId, String clientId){
        return iTmtUserRoleRepo.findAllByUserIdAndRoleOriginSystemClientId(userId, clientId);
    }

    @Transactional(readOnly = true)
    public List<TmtRole> findRolesByUserId(Long userId){
        Specification<TmtUserRole> s = (root, query, cb) -> {
            Predicate p = cb.equal(root.get("user").get("id"), userId);
            return query.where(p).getRestriction();
        };
        List<TmtUserRole> userRoles = iTmtUserRoleRepo.findAll(s);
        return userRoles.stream().map(TmtUserRole::getRole).distinct().collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<TmtRole> findRolesByUserIdAndClientId(Long userId, String clientId){
        List<TmtUserRole> userRoles = findByUserIdAndClientId(userId, clientId);
        return userRoles.stream().map(TmtUserRole::getRole).distinct().collect(Collectors.toList());
    }

    public void deleteByRoleId(long roleId){
        Specification<TmtUserRole> s = (root, query, cb) -> {
            Predicate p = cb.equal(root.get("role").get("id"), roleId);
            return query.where(p).getRestriction();
        };
        List<TmtUserRole> list = iTmtUserRoleRepo.findAll(s);
        iTmtUserRoleRepo.deleteInBatch(list);
    }

    public void deleteBy(String clientId, Long userId, List<String> roleCodes){
        Specification<TmtUserRole> s = (root, query, cb) -> {
            Predicate p1 = cb.equal(root.get("role").get("originSystem").get("clientId"), clientId);
            Predicate p2 = cb.in(root.get("role").get("code")).value(roleCodes);
            Predicate p3 = cb.equal(root.get("user").get("id"), userId);
            Predicate p = cb.and(p1, p2, p3);
            return query.where(p).getRestriction();
        };
        List<TmtUserRole> list = iTmtUserRoleRepo.findAll(s);
        if (list != null)
            iTmtUserRoleRepo.deleteInBatch(list);
    }

    @Transactional(readOnly = true)
    public List<TmtUserRole> findByUserIdWithOriginSystemAndRolesAndAuthorities(Long id, String clientId) {
        List<TmtUserRole> userRoles = iTmtUserRoleRepo.findAllByUserIdAndRoleOriginSystemClientId(id,clientId);
        loadLazyProperties(userRoles, new String[]{"role.originSystem", "role.roleAuthorities"});
        return userRoles;
    }

    @Transactional(readOnly = true)
    public List<TmtUserRole> findAllByUserId(Long id) {
        List<TmtUserRole> userRoles = iTmtUserRoleRepo.findAllByUserId(id);
        loadLazyProperties(userRoles, new String[]{"role.originSystem", "role.roleAuthorities"});
        return userRoles;
    }

    private List<TmtUserRole> findByUserIdAndClientId(Long userId, String clientId){
        Specification<TmtUserRole> s = (root, query, cb) -> {
            Predicate p1 = cb.equal(root.get("role").get("originSystem").get("clientId"), clientId);
            Predicate p2 = cb.equal(root.get("user").get("id"), userId);
            Predicate p = cb.and(p1, p2);
            return query.where(p).getRestriction();
        };
        return iTmtUserRoleRepo.findAll(s);
    }


 
}
